/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package FEMSolver1D;

import FEMShapeFunction1D.FEMShapeFunction1D1;
import HashMatrix2.HashMatrix2;
import HashMatrix2.LUFactorization;
import Integration.IFunction1D;
import MathLib.HashMatrix.Gauss;
import MathLib.HashMatrix.HashMatrix;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import jmeshless.NewOkCancelDialog;

import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import syntaxanalyser.PostfiksX;
/**
 *
 * @author mark_o
 */
public class MainMatrixGenerator1{

    public HashMatrix2 A;
//    HashMatrix A;
    public double[] b;
    ArrayList<Double> NodeList;
    public ArrayList<FEMShapeFunction1D1> FuncList;

    String pString="1";
    String wString="0";
    String qString="10";
    String fString="100";

    double left;
    double right;

    boolean DirihetA;
    double AVal;
    boolean DirihetB;
    double BVal;


    public MainMatrixGenerator1(ArrayList<Double> NodeList) {
        this.NodeList = NodeList;
        A = new HashMatrix2(HashMatrix2.ARRAY_TYPE, NodeList.size());
        b = new double[NodeList.size()];
        generateFunctions();

    }

    private void generateFunctions(){
        FuncList = new ArrayList<FEMShapeFunction1D1>();
        double h = NodeList.get(1) - NodeList.get(0);
        for (int i = 0; i < NodeList.size(); i++) {
            FuncList.add(new FEMShapeFunction1D1(NodeList.get(i), h));
        }
    }

    public void Generate() {
        MatrixGenerator1 gen = new MatrixGenerator1(NodeList.get(0),NodeList.get(NodeList.size()-1));

        gen.setLeft(left);
        gen.setRight(right);

        IFunction1D p = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(pString, x);
                } catch (Exception ex) {
                    Logger.getLogger(MainMatrixGenerator1.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        IFunction1D w = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(wString, x);
                } catch (Exception ex) {
                    Logger.getLogger(MainMatrixGenerator1.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        IFunction1D q = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(qString, x);
                } catch (Exception ex) {
                    Logger.getLogger(MainMatrixGenerator1.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        IFunction1D f = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(fString, x);
//                	if(x>0.5){return -1;}else{return 1;}
                } catch (Exception ex) {
                    Logger.getLogger(MainMatrixGenerator1.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };

        for (int i = 0; i < b.length; i++) {
            //IFunction1D f1 = FuncList.get(i);
            gen.setF1(FuncList.get(i));
            gen.setF2(FuncList.get(i));
            //A.setValue(i, i, gen.getKe(p)+gen.getAdv(w)+gen.getMe(q));
            for (int j = 0; j < b.length; j++) {
                gen.setF2(FuncList.get(j));
                double val = gen.getKe(p)+gen.getAdv(w)+gen.getMe(q);
                A.setValue(i, j, val);
            }
            b[i] = gen.getFe(f);
        }

//        for (int i = 0; i < b.length; i++) {
//            for (int j = 0; j < b.length; j++) {
//                System.out.print(A.getValue(i, j)+"\t");
//            }
//            System.out.println("\t"+b[i]);
//        }

    }

    public void applyBounderiesForCoupling(){
        if (DirihetA) {
            b[0] = AVal;
            b[1]-= AVal*A.getValue(1, 0);
            A.setValue(0, 0, 1);
            A.setValue(0, 1, 0);
            A.setValue(1, 0, 0);
        }else{
            b[0]+=AVal;
        }
        

        //Dirihlet b:
        if (DirihetB) {
            b[b.length-1] = BVal;
            b[b.length-2]-= BVal*A.getValue(b.length-2, b.length-1);
            A.setValue(A.getN()-1, A.getN()-1, 1);
            A.setValue(A.getN()-1, A.getN()-2, 0);
            A.setValue(A.getN()-2, A.getN()-1, 0);
        }else{
            b[b.length-1]+=BVal;
        }
    }


    public double[] Solve(String outPath){
        
//        Gauss lu = new Gauss(A);

        //Neyman a:
        //b[0]+=1;

        //Dirihlet a:
        if (DirihetA) {
            b[0] = AVal;
            b[1]-= AVal*A.getValue(1, 0);
            A.setValue(0, 0, 1);
            A.setValue(0, 1, 0);
            A.setValue(1, 0, 0);
        }else{
            b[0]+=AVal;
        }
        

        //Dirihlet b:
        if (DirihetB) {
            b[b.length-1] = BVal;
            b[b.length-2]-= BVal*A.getValue(b.length-2, b.length-1);
            A.setValue(A.getN()-1, A.getN()-1, 1);
            A.setValue(A.getN()-1, A.getN()-2, 0);
            A.setValue(A.getN()-2, A.getN()-1, 0);
        }else{
            b[b.length-1]+=BVal;
        }
        LUFactorization lu = new LUFactorization(A);
        double[] res = lu.calculate(b);
//        for (int j = 0; j < b.length; j++) {
//            System.out.println(NodeList.get(j)+"\t"+res[j]);
//        }
        return res;
    }

    public ArrayList<Double> generateBFEM(boolean left){
        MatrixGenerator1 gen = new MatrixGenerator1(NodeList.get(0),NodeList.get(NodeList.size()-1));

//        gen.setLeft(this.left-NodeList.get(1)+NodeList.get(0));
//        gen.setRight(this.right+NodeList.get(1)-NodeList.get(0));
        gen.setLeft(this.left);
        gen.setRight(this.right);
        if(left){
            gen.setF1(FuncList.get(0));
        }else{
            gen.setF1(FuncList.get(FuncList.size()-1));
        }

        ArrayList<Double> res = new ArrayList<Double>();
        IFunction1D constF = new IFunction1D() {

            public double calculate(double x) {
                return 1.0;
            }

            public double calculateDerivaty(double x) {
                return 0.0;
            }
        };
        for (int i = 0; i < FuncList.size(); i++) {
            gen.setF2(FuncList.get(i));
            res.add(gen.getMe(constF));
        }

        return res;
    }

    public ArrayList<Double> generateBFEMPox(boolean left){
        MatrixGenerator1 gen = new MatrixGenerator1(NodeList.get(0),NodeList.get(NodeList.size()-1));

        gen.setLeft(this.left-NodeList.get(1)+NodeList.get(0));
        gen.setRight(this.right+NodeList.get(1)-NodeList.get(0));
        if(left){
            gen.setF1(FuncList.get(0));
        }else{
            gen.setF1(FuncList.get(FuncList.size()-1));
        }

        ArrayList<Double> res = new ArrayList<Double>();
        IFunction1D constF = new IFunction1D() {

            public double calculate(double x) {
                return 1.0;
            }

            public double calculateDerivaty(double x) {
                return 0.0;
            }
        };
        for (int i = 0; i < FuncList.size(); i++) {
            gen.setF2(FuncList.get(i));
            res.add(gen.getAdv(constF));
        }

        return res;
    }

    public HashMatrix2 getA() {
        return A;
    }

    public double[] getB() {
        return b;
    }

    public void setAVal(double AVal) {
        this.AVal = AVal;
    }

    public void setBVal(double BVal) {
        this.BVal = BVal;
    }

    public void setDirihetA(boolean DirihetA) {
        this.DirihetA = DirihetA;
    }

    public void setDirihetB(boolean DirihetB) {
        this.DirihetB = DirihetB;
    }

    public void setfString(String fString) {
        this.fString = fString;
    }

    public void setpString(String pString) {
        this.pString = pString;
    }

    public void setqString(String qString) {
        this.qString = qString;
    }

    public void setwString(String wString) {
        this.wString = wString;
    }

    public void setLeft(double left) {
        this.left = left;
    }

    public void setRight(double right) {
        this.right = right;
    }

    public static void main(String[] args){
        ArrayList<Double> list = new ArrayList<Double>();
        double a = 0.0;
        double b = 1.0;
        int N = 200;
        double h = (b-a)/N;
        for (int i = 0; i <= N; i++) {
            list.add(a+h*i);
        }
        //FEMShapeFunction1D1 f = new FEMShapeFunction1D1(0.5, 0.5);
        //for (int i = 0; i <= N; i++) {
        //    System.out.println((a+h*i)+"\t\t"+f.calculateDerivaty(a+h*i));
        //}
        MainMatrixGenerator1 gen = new MainMatrixGenerator1(list);

        gen.setLeft(a);
            gen.setRight(b);
            gen.setfString("100");
            gen.setwString("100");
            gen.setqString("0");
            gen.setpString("1");
            gen.setDirihetB(true);
            gen.setBVal(0.0);
            gen.setDirihetA(true);
            gen.setAVal(0.0);
            
        gen.Generate();
        double[] res = gen.Solve("");
        
        XYSeries s2 = new XYSeries("differences", true, true);

        for (int i = 0; i < res.length; i++) {
			s2.add(a+i*h, res[i]);
		}
        
        XYSeriesCollection col = new XYSeriesCollection();
        col.addSeries(s2);
        NewOkCancelDialog d = new NewOkCancelDialog(null, false, col);
        d.setLocationRelativeTo(null);
        d.setVisible(true);
    }
}